#!/bin/bash
##############################
# NOTES: If using externally (i.e. through WAN interface, ensure ports are forwarded to the central server
#
# TODO : 
#	 	1. add nodes to LANS's i.e. home/work etc so wol can be relayed via online nodes
#       2. Obtain patch status on all online nodes.
##############################
# CHANGELOG
# v1.0  20/08/2011   SIFTU: Initial release to the public
# v1.1  24/08/2011   SIFTU: Added menu options s|w|h|r|d and supporting functions
#                           Allow quick node_status check using tcping if installed
# v1.2  26/08/2011   SIFTU: Adding option to vnc into remote machine  "v"
##############################
# Constant and variable declaration
##############################
timeout="5"
config_file="$HOME/bin/reverse_ssh.conf"
number_hosts=$(wc -l $config_file | awk {'print $1'})
central_server="server"
tunnel_endpoint="server fqdn"


##############################
# Lets run some checks to make sure all is in order
##############################
if [ $(hostname -s) = $central_server ]; then
	sshserver="localhost"
else
    sshserver="$(echo $tunnel_endpoint)"
fi

if [ -e $config_file ]; then
	echo "Found config file.."
else 
	echo "No config file found. Please correct"
	exit 1
fi

##############################
# function to check if command is installed and in $PATH
##############################
command_exists () 
{
    type -P "$1" &> /dev/null ;
}

##############################
# Read in the config file to arrays (1 for each host/line)
##############################
index="0"
while read line; do 
	host[$index]="$line"
	index=$(( $index+1 ))
done < $config_file

##############################
# use awk to get port values from the array i.e. find the port
##############################
function getport()
{
	port=$(echo "${host[$1]}" | awk -F";" '{print $2}')
}
##############################
# use awk to get user values from the array i.e. find the port
##############################
function getuser()
{
    remoteuser=$(echo "${host[$1]}" | awk -F";" '{print $3}')
}

##############################
# use awk to get MAC address values from the array 
##############################
function getmac()
{
	remotemac=$(echo "${host[$1]}" | awk -F";" '{print $4}')

}

##############################
# use awk to get user hostname from the array i.e. find the port
##############################
function gethost()
{
    remotehost=$(echo "${host[$1]}" | awk -F";" '{print $1}')
}

status() {
##############################
# Find out if node is online and has established a reverse ssh connection
##############################

# Check to see if we can quick connect to ports using tcping
# This improves the refresh rate of the menu
command_exists tcping
if [ $? -eq 0 ]; then
    node_status=$(tcping $sshserver $port > /dev/null && (echo -en '\E[32;32m'"\033[1mOnline\033[0m";tput sgr0;) || (echo -en '\E[31;31m'"\033[1mOffline\033[0m";tput sgr0) &)
else
    node_status=$(ssh -q -o "ConnectTimeout $timeout" -p $port $remoteuser@$sshserver exit && (echo -en '\E[32;32m'"\033[1mOnline\033[0m";tput sgr0;) || (echo -en '\E[31;31m'"\033[1mOffline\033[0m";tput sgr0) &)
fi
stat_noncolor=$(echo $node_status|sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g")
stat_noncolor=$(echo $stat_noncolor|sed "s/\o033//;s/(B//g")
##############################
# Find out Linux distro if the node is online and display distro name
##############################
if [ "$stat_noncolor" = "Online" -a "$opt" = "d" ]; then
	node_distro=$(ssh -p $port $remoteuser@$sshserver "lsb_release -d"|awk -F: '{$1="";sub(/^[[:blank:]]*/,"")}1')
else
	node_distro=""	
fi
}


##############################
# executes a shell session to the remote node with 
##############################
connect_server()
{
	clear;echo "";
        getport $1
        getuser $1
        ssh -X -p $port $remoteuser@$sshserver;
        echo " "
}

##############################
# executes given command on the remote node (Good for remote shutdown etc)
##############################
shutdown()
{
    echo -n "Enter node number to shutdown: "
    read opt
    getport $opt
    getuser $opt
	ssh -t -p $port $remoteuser@$sshserver 'sudo shutdown -h now'
    read -p "Press any key to return to the main menu..." 
}

##############################
# Print the help screen
##############################
help()
{
    clear
    echo -e "  H E L P - M E N U\n"
    echo -e "\t0 - XX\t Press the number of the node you would like to connect to"
    echo -e "\ts\t Run \"sudo shutdown -h now\" on remote node"
    echo -e "\tw\t Send wake-on-lan magic packet to node. NOTE: this must be"
    echo -e "\t\t run from a machine connect on the same LAN"
    echo -e "\tr\t refresh main menu and update node status"
    echo -e "\tv\t establish vnc connection over reverse ssh connection"
    echo -e "\td\t display the linux distro information\n"
    read -p "Press any key to return to the main menu..." 
}
##############################
# Print the wake-on-lan screen for nodes which are offline
##############################
wake_on_lan()
{
    command_exists wakeonlan
    if [ $? -eq 0 ]; then
        echo -n "Enter node to send wol request to: "
        read wol
        getmac $wol
        wakeonlan $remotemac
        echo "Issuing command: wakeonlan $remotemac"
    else
	echo "Command \"wakeonlan\" does not exist on this node, please install"         
    fi
    read -p "Press any key to return to the main menu..." 
}

##############################
# Connect to vnc server on remote node
##############################
function connect_vnc()
{

        echo -n "Enter node to vnc to: "
        read vnc
    	getport $vnc
    	getuser $vnc
        echo -n "Enter reverse ssh port_number to use for vnc connection: "
        read ssh_vnc_port
## Set up iptables to only allow connections from $sshserver
	    nohup ssh -t -p $port $remoteuser@$sshserver "nohup x11vnc -display :0 && autossh -f -N -R *:$ssh_vnc_port:localhost:5900 $sshserver -oLogLevel=error  -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no"
## Start the vncviewer to connect using the reverse ssh tunnel
        vncviewer $sshserver:$ssh_vnc_port
}

##############################
# MAIN CALL
##############################

clear

while :
do
    clear
    echo "  M A I N - M E N U"
##############################
# Generate the menu from the config file
##############################
    menuindex=0
    tput_column=45
    tput_row=1
    while [ "$menuindex" -lt "$number_hosts" ]; do
    	gethost $menuindex
    	getport $menuindex
    	getuser $menuindex
    	status $menuindex
    	echo -e "$menuindex. [$node_status]\t $remotehost"
    	tput cup $tput_row $tput_column
    	echo "$node_distro"
    	tput sgr0
    	menuindex=$(( $menuindex+1 ))
    	tput_row=$(( $tput_row+1 ))
    done
    echo ""
    echo -n "Enter option [0-$(( $number_hosts-1 ))] or \"d|h|r|s|w|x\": "
    read opt
    case $opt in
    	[0-9]) connect_server $opt;;
    	[0-9][0-9]) connect_server $opt;;
        d) status ;;
        s) shutdown  ;;
        w) wake_on_lan ;;
        h) help ;;
        r) status ;;
        v) connect_vnc ;;
    	x) clear; exit 0;;
    	*) clear; echo "$opt is an invaild option." && sleep 2;;
esac
done
